---
title: Prawf
date: 2022-02-19
description: A Pauli Test Simulation app made with Web Component and RxJS
demo: https://prawf.vercel.app
source: https://github.com/elianiva/prawf
type: personal
stack:
    - ["Web Component", "https://developer.mozilla.org/en-US/docs/Web/Web_Components"]
    - ["RxJS", "https://rxjs.dev/"]
    - ["Typescript", "https://www.typescriptlang.org/"]
---

**Prawf** is a Pauli Test simulation app made with Web Component and RxJS. You can find the reason why I made this in [the project repo](https://github.com/elianiva/prawf)

## Web Component

I chose Web Component because I want to try to experiment with it. I used it briefly in the past and I have no idea what I'm doing so I want to try to use it again.

## Styling

I was going to use [Tailwind](https://tailwindcss.com/) but then I realised I use Web Component and I have no idea how to set it up. The second option is [Open Props](https://open-props.style/) but then I thought it's a bit overkill for what I'm doing.

Since I don't use Web Component that much, there are probably some questionable things that I've done, and one of them is importing CSS as a string and then including it in the template.

I imported the css string using `?inline` directive from Vite to import a file as a string. The result is... there are quite a lot of unnecessary whitespaces which makes the final HTML bigger. I'm sure I could _probably_ minify it, but it's fine for now.

One of the things that I like from Web Component is component isolation; meaning that other component won't touch each other, they're isolated. This is good and bad, the good is I don't need to worry about accidentally touching other components, the bad is I duplicated a bunch of CSS because I couldn't use utility classes.

Oh, I also added a darkmode with an animated toggle button because why not ツ It isn't persisted, though.

## Reactivity

Making something Reactive is very easy thanks to RxJS. I don't think I struggle that much in this section. Again, I don't use RxJS that much so there is definitely room for improvement.

For example, I re-render the entire component instead of modifying the node that I changed because I feel re-rendering the entire thing is a lot simpler and I don't think it slows my app.

## State Management

I use Svelte quite a bit, so I tried to make `svelte/store`-style state management using RxJS Subject. Here's an example.

```typescript
export let currentTheme: Theme = "light";
export const currentTheme$ = new Subject<ThemeState>();
currentTheme$.subscribe(({ current }) => {
	currentTheme = current;
});
```

I use a variable to persist the last state because I couldn't find a way to "get" the last value from RxJS Subject.

## Routing

I made a Subject to change the route. The way it works is actually pretty simple. Whenever I want to navigate to another page, I just need to emit a path as a string to the Subject and it will change the route using `history.pushState`.

## Chart

I decided to build the chart myself instead of using a library since I only need two; which are lines and bars. I decided to make a smooth curved line. Thanks to [this post](https://francoisromain.medium.com/smooth-a-svg-path-with-cubic-bezier-curves-e37b49d46c74) that I found, I was able to make the chart.

## History and Countdown

I used RxJS `interval` and `timer` for the countdown timer and just re-render every second. I used css transition for the top bar instead of re-rendering every time because I want it to animate smoothly when it gets shorter.

For the game history, I just pushed an object to a Subject. I also have a `currentRound` Subject that keeps getting updated by an `interval` Observable which tracks the current round.

## Result Calculation

The result is calculated from the correct answers, incorrect answers, the percentage of the correct answer, answers per round in average, and the standard deviation.

I didn't know how to decide a smoother chart (consistent) is better than a jagged chart (inconsistent). Fortunately, people at [Teknologi Umum](https://t.me/teknologi_umum) pointed me in the right direction, which was to find the standard deviation. It's just simple math, apparently. I was expecting something more involved but no, it's just a quick formula that could be done in less than a minute.
